package com.example.a_java.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.a_java.dto.*;
import com.example.a_java.entity.ContractAttachment;
import com.example.a_java.entity.ContractSignatory;
import com.example.a_java.entity.LoanApply;
import com.example.a_java.entity.LoanContract;
import com.example.a_java.entity.LoanRepaymentPlan;
import com.example.a_java.mapper.*;
import com.example.a_java.service.ContractService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 合同管理Service实现
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ContractServiceImpl extends ServiceImpl<LoanContractMapper, LoanContract> implements ContractService {

    private final LoanContractMapper contractMapper;
    private final ContractAttachmentMapper attachmentMapper;
    private final ContractSignatoryMapper signatoryMapper;
    private final LoanApplyMapper loanApplyMapper;
    private final LoanRepaymentPlanMapper repaymentPlanMapper;
    
    @Value("${file.upload.path:/upload}")
    private String uploadPath;
    
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    public IPage<Map<String, Object>> getContractList(ContractListDTO contractListDTO) {
        // 创建分页对象
        Page<Map<String, Object>> page = new Page<>(contractListDTO.getPageNum(), contractListDTO.getPageSize());
        
        // 调用Mapper查询
        return contractMapper.selectContractList(
                page,
                contractListDTO.getContractNo(),
                contractListDTO.getCustomerName(),
                contractListDTO.getType(),
                contractListDTO.getStatus(),
                contractListDTO.getStartTime(),
                contractListDTO.getEndTime()
        );
    }
    
    @Override
    public ContractDetailDTO getContractDetail(Long contractId) {
        // 查询合同基本信息
        ContractDetailDTO contractDetail = contractMapper.selectContractById(contractId);
        if (contractDetail == null) {
            return null;
        }
        
        // 查询合同附件列表
        List<ContractDetailDTO.AttachmentDTO> attachments = attachmentMapper.selectAttachmentsByContractId(contractId);
        contractDetail.setAttachments(attachments);
        
        // 查询合同签署方列表
        List<ContractDetailDTO.SignatoryDTO> signatories = signatoryMapper.selectSignatoriesByContractId(contractId);
        contractDetail.setSignatories(signatories);
        
        return contractDetail;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> generateContract(ContractGenerateDTO generateDTO) {
        // 查询贷款申请
        LoanApply loanApply = loanApplyMapper.selectOne(
                new LambdaQueryWrapper<LoanApply>()
                        .eq(LoanApply::getApplyNo, generateDTO.getLoanNo())
                        .eq(LoanApply::getIsDeleted, 0)
        );
        
        if (loanApply == null) {
            throw new RuntimeException("贷款申请不存在");
        }
        
        // 生成合同编号
        String contractNo = generateContractNo();
        
        // 创建合同对象
        LoanContract contract = new LoanContract();
        contract.setContractNo(contractNo);
        contract.setApplyId(loanApply.getApplyId());
        contract.setCustId(loanApply.getCustId());
        contract.setLoanAmount(loanApply.getLoanAmount());
        contract.setLoanTerm(loanApply.getLoanTerm());
        contract.setLoanPurpose(loanApply.getLoanPurpose());
        contract.setRepayMethod(loanApply.getRepayMethod());
        contract.setGuarMethod(loanApply.getGuarMethod());
        contract.setInterestRate(generateDTO.getInterestRate());
        contract.setSignDate(LocalDate.parse(generateDTO.getSignDate(), DATE_FORMATTER));
        contract.setStartDate(LocalDate.parse(generateDTO.getEffectiveDate(), DATE_FORMATTER));
        contract.setEndDate(LocalDate.parse(generateDTO.getExpiryDate(), DATE_FORMATTER));
        contract.setContractStatus(10); // 待签署
        contract.setContractType(StringUtils.hasText(generateDTO.getGuaranteeType()) ? generateDTO.getGuaranteeType() : "loan");
        contract.setRemark(generateDTO.getRemark());
        
        // 根据模板生成合同内容（这里简化处理，实际应该使用模板引擎
        StringBuilder contentBuilder = new StringBuilder();
        contentBuilder.append("贷款合同\n\n");
        contentBuilder.append("合同编号").append(contractNo).append("\n");
        contentBuilder.append("签订日期").append(generateDTO.getSignDate()).append("\n\n");
        contentBuilder.append("甲方（借款人）").append(generateDTO.getBorrower()).append("\n");
        contentBuilder.append("证件号码").append(generateDTO.getBorrowerIdCard()).append("\n\n");
        contentBuilder.append("乙方（贷款人）：").append(generateDTO.getLender()).append("\n");
        contentBuilder.append("法定代表人：").append(generateDTO.getLenderRepresentative()).append("\n\n");
        contentBuilder.append("担保方式").append(generateDTO.getGuaranteeType()).append("\n");
        if ("guarantee".equals(generateDTO.getGuaranteeType()) && StringUtils.hasText(generateDTO.getGuarantor())) {
            contentBuilder.append("担保人：").append(generateDTO.getGuarantor()).append("\n\n");
        } else if (("mortgage".equals(generateDTO.getGuaranteeType()) || "pledge".equals(generateDTO.getGuaranteeType())) 
                && StringUtils.hasText(generateDTO.getCollateralDesc())) {
            contentBuilder.append("抵押物描述：").append(generateDTO.getCollateralDesc()).append("\n\n");
        }
        contentBuilder.append("贷款金额").append(loanApply.getLoanAmount()).append("元\n");
        contentBuilder.append("贷款期限").append(loanApply.getLoanTerm()).append("个月\n");
        contentBuilder.append("贷款利率").append(generateDTO.getInterestRate()).append("%\n");
        contentBuilder.append("贷款用途：").append(loanApply.getLoanPurpose()).append("\n\n");
        contentBuilder.append("生效日期").append(generateDTO.getEffectiveDate()).append("\n");
        contentBuilder.append("到期日期").append(generateDTO.getExpiryDate()).append("\n\n");
        contentBuilder.append("甲方（借款人）签章：____________\n\n");
        contentBuilder.append("乙方（贷款人）签章：____________\n\n");
        if ("guarantee".equals(generateDTO.getGuaranteeType()) && StringUtils.hasText(generateDTO.getGuarantor())) {
            contentBuilder.append("担保人签章：____________\n\n");
        }
        
        contract.setContent(contentBuilder.toString());
        
        // 保存合同
        save(contract);
        
        // 创建签署方
        ContractSignatory borrower = new ContractSignatory();
        borrower.setContractId(contract.getContractId());
        borrower.setRole("borrower");
        borrower.setName(generateDTO.getBorrower());
        borrower.setIdType("ID_CARD");
        borrower.setIdNumber(generateDTO.getBorrowerIdCard());
        borrower.setSignStatus("unsigned");
        signatoryMapper.insert(borrower);
        
        ContractSignatory lender = new ContractSignatory();
        lender.setContractId(contract.getContractId());
        lender.setRole("lender");
        lender.setName(generateDTO.getLender());
        lender.setIdType("BUSINESS_LICENSE");
        lender.setIdNumber(""); // 实际应该填写企业信用代码
        lender.setSignStatus("unsigned");
        signatoryMapper.insert(lender);
        
        // 如果有担保人，添加担保人签署方
        if ("guarantee".equals(generateDTO.getGuaranteeType()) && StringUtils.hasText(generateDTO.getGuarantor())) {
            ContractSignatory guarantor = new ContractSignatory();
            guarantor.setContractId(contract.getContractId());
            guarantor.setRole("guarantor");
            guarantor.setName(generateDTO.getGuarantor());
            guarantor.setIdType("ID_CARD");
            guarantor.setIdNumber(""); // 实际应该填写担保人证件号
            guarantor.setSignStatus("unsigned");
            signatoryMapper.insert(guarantor);
        }
        
        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("contractId", contract.getContractId());
        result.put("contractNo", contractNo);
        result.put("previewUrl", "/contract/preview/" + contract.getContractId());
        
        return result;
    }
    
    @Override
    public void previewContract(Long contractId, OutputStream outputStream) {
        downloadContract(contractId, outputStream);
    }
    
    @Override
    public void downloadContract(Long contractId, OutputStream outputStream) {
        LoanContract contract = getById(contractId);
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        // 查找是否有签署后的PDF附件
        ContractAttachment attachment = attachmentMapper.selectOne(
                new LambdaQueryWrapper<ContractAttachment>()
                        .eq(ContractAttachment::getContractId, contractId)
                        .eq(ContractAttachment::getFileType, "application/pdf")
                        .eq(ContractAttachment::getIsDeleted, 0)
                        .orderByDesc(ContractAttachment::getUploadTime)
                        .last("LIMIT 1")
        );
        
        try {
            if (attachment != null && attachment.getFilePath() != null) {
                // 如果有PDF附件，直接返回附件
                Files.copy(Paths.get(attachment.getFilePath()), outputStream);
            } else {
                // 否则生成一个临时的文本文件
                String content = contract.getContent() != null ? contract.getContent() : "合同内容暂未生成";
                outputStream.write(content.getBytes());
            }
        } catch (IOException e) {
            log.error("下载合同文件失败", e);
            throw new RuntimeException("下载合同文件失败: " + e.getMessage());
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateContractStatus(ContractStatusUpdateDTO updateDTO) {
        LoanContract contract = getById(updateDTO.getContractId());
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        // 根据状态字符串获取状态码
        Integer statusCode = getStatusCodeByString(updateDTO.getStatus());
        if (statusCode == null) {
            throw new RuntimeException("无效的状态");
        }
        
        // 更新合同状态
        LoanContract updateContract = new LoanContract();
        updateContract.setContractId(updateDTO.getContractId());
        updateContract.setContractStatus(statusCode);
        updateContract.setRemark(updateDTO.getRemark());
        
        return updateById(updateContract);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean signContract(ContractSignDTO signDTO) {
        LoanContract contract = getById(signDTO.getContractId());
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        if (contract.getContractStatus() != 10) {
            throw new RuntimeException("当前合同状态不允许签署");
        }
        
        // 解析签署时间
        LocalDateTime signTime = LocalDateTime.parse(signDTO.getSignTime(), DATETIME_FORMATTER);
        
        // 更新合同状态为已签署
        LoanContract updateContract = new LoanContract();
        updateContract.setContractId(signDTO.getContractId());
        updateContract.setContractStatus(20); // 已签署
        updateContract.setSignTime(signTime);
        updateContract.setRemark(signDTO.getRemark());
        
        boolean updated = updateById(updateContract);
        if (!updated) {
            return false;
        }
        
        // 更新签署方状态
        List<ContractSignatory> signatories = signatoryMapper.selectList(
                new LambdaQueryWrapper<ContractSignatory>()
                        .eq(ContractSignatory::getContractId, signDTO.getContractId())
                        .eq(ContractSignatory::getIsDeleted, 0)
        );
        
        for (ContractSignatory signatory : signatories) {
            signatory.setSignStatus("signed");
            signatory.setSignTime(signTime);
            signatory.setSignMethod(signDTO.getMethod());
            signatoryMapper.updateById(signatory);
        }
        
        // 保存附件（如果有）
        if (signDTO.getAttachments() != null && !signDTO.getAttachments().isEmpty()) {
            saveAttachments(signDTO.getContractId(), signDTO.getAttachments());
        }
        
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean terminateContract(ContractTerminateDTO terminateDTO) {
        LoanContract contract = getById(terminateDTO.getContractId());
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        // 检查合同状态，只有已签署或已生效的合同才能终止
        if (contract.getContractStatus() != 20 && contract.getContractStatus() != 30) {
            throw new RuntimeException("当前合同状态不允许终止");
        }
        
        // 更新合同状态为已终止
        LoanContract updateContract = new LoanContract();
        updateContract.setContractId(terminateDTO.getContractId());
        updateContract.setContractStatus(50); // 已终止
        updateContract.setTerminateReason(terminateDTO.getReason());
        updateContract.setTerminateDate(LocalDate.parse(terminateDTO.getTerminateDate(), DATE_FORMATTER));
        updateContract.setRemark(terminateDTO.getRemark());
        
        return updateById(updateContract);
    }
    
    @Override
    public RepaymentPlanDTO getRepaymentPlan(Long contractId) {
        // 查询合同
        LoanContract contract = getById(contractId);
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        // 查询还款计划
        List<LoanRepaymentPlan> plans = repaymentPlanMapper.selectList(
                new LambdaQueryWrapper<LoanRepaymentPlan>()
                        .eq(LoanRepaymentPlan::getContractId, contractId)
                        .eq(LoanRepaymentPlan::getIsDeleted, 0)
                        .orderByAsc(LoanRepaymentPlan::getTermNo)
        );
        
        // 组装结果
        RepaymentPlanDTO repaymentPlanDTO = new RepaymentPlanDTO();
        repaymentPlanDTO.setContractId(contractId);
        repaymentPlanDTO.setContractNo(contract.getContractNo());
        repaymentPlanDTO.setLoanAmount(contract.getLoanAmount());
        repaymentPlanDTO.setTerm(contract.getLoanTerm());
        repaymentPlanDTO.setInterestRate(contract.getInterestRate());
        
        // 设置还款方式名称
        String repayMethodName;
        switch (contract.getRepayMethod()) {
            case 1:
                repayMethodName = "等额本息";
                break;
            case 2:
                repayMethodName = "等额本金";
                break;
            case 3:
                repayMethodName = "先息后本";
                break;
            case 4:
                repayMethodName = "一次性还本付息";
                break;
            default:
                repayMethodName = "未知";
        }
        repaymentPlanDTO.setRepayMethod(repayMethodName);
        
        // 计算总利息和总金额
        BigDecimal totalInterest = BigDecimal.ZERO;
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<RepaymentPlanDTO.PlanItemDTO> planItems = new ArrayList<>();
        
        for (LoanRepaymentPlan plan : plans) {
            RepaymentPlanDTO.PlanItemDTO item = new RepaymentPlanDTO.PlanItemDTO();
            item.setId(plan.getPlanId());
            item.setTermNo(plan.getTermNo());
            item.setRepayDate(plan.getRepayDate().format(DATE_FORMATTER));
            item.setPrincipal(plan.getPrincipal());
            item.setInterest(plan.getInterest());
            item.setAmount(plan.getRepayAmount());
            item.setPrincipalBalance(plan.getPrincipalBalance());
            
            // 设置还款状态
            String status;
            switch (plan.getRepayStatus()) {
                case 10:
                    status = "pending";
                    break;
                case 20:
                    status = "paid";
                    break;
                case 30:
                    status = "overdue";
                    break;
                default:
                    status = "unknown";
            }
            item.setStatus(status);
            
            planItems.add(item);
            
            // 累计总额
            totalInterest = totalInterest.add(plan.getInterest());
            totalAmount = totalAmount.add(plan.getRepayAmount());
        }
        
        repaymentPlanDTO.setTotalInterest(totalInterest);
        repaymentPlanDTO.setTotalAmount(totalAmount);
        repaymentPlanDTO.setPlans(planItems);
        
        return repaymentPlanDTO;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int generateRepaymentPlan(Long contractId) {
        // 查询合同
        LoanContract contract = getById(contractId);
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }
        
        // 检查是否已经生成过还款计划
        long count = repaymentPlanMapper.selectCount(
                new LambdaQueryWrapper<LoanRepaymentPlan>()
                        .eq(LoanRepaymentPlan::getContractId, contractId)
                        .eq(LoanRepaymentPlan::getIsDeleted, 0)
        );
        
        if (count > 0) {
            throw new RuntimeException("合同已经生成过还款计划");
        }
        
        // 生成还款计划
        List<LoanRepaymentPlan> plans = generatePlans(contract);
        
        // 保存还款计划
        for (LoanRepaymentPlan plan : plans) {
            repaymentPlanMapper.insert(plan);
        }
        
        return plans.size();
    }
    
    /**
     * 生成还款计划列表
     * @param contract 合同信息
     * @return 还款计划列表
     */
    private List<LoanRepaymentPlan> generatePlans(LoanContract contract) {
        List<LoanRepaymentPlan> plans = new ArrayList<>();
        
        // 贷款金额
        BigDecimal loanAmount = contract.getLoanAmount();
        // 期数
        int term = contract.getLoanTerm();
        // 月利率
        BigDecimal monthRate = contract.getInterestRate().divide(new BigDecimal("100"), 8, RoundingMode.HALF_UP)
                .divide(new BigDecimal("12"), 8, RoundingMode.HALF_UP);
        // 还款方式
        int repayMethod = contract.getRepayMethod();
        // 开始日期
        LocalDate startDate = contract.getStartDate();
        
        // 根据不同的还款方式生成还款计划
        switch (repayMethod) {
            case 1: // 等额本息
                generateEqualInstallmentPlans(plans, loanAmount, term, monthRate, startDate);
                break;
            case 2: // 等额本金
                generateEqualPrincipalPlans(plans, loanAmount, term, monthRate, startDate);
                break;
            case 3: // 先息后本
                generateInterestFirstPlans(plans, loanAmount, term, monthRate, startDate);
                break;
            case 4: // 一次性还本付息
                generateBulletPlans(plans, loanAmount, term, monthRate, startDate);
                break;
            default:
                throw new RuntimeException("不支持的还款方式: " + repayMethod);
        }
        
        // 设置合同ID和其他公共字段
        for (LoanRepaymentPlan plan : plans) {
            plan.setContractId(contract.getContractId());
            plan.setRepayStatus(10); // 未还
        }
        
        return plans;
    }
    
    /**
     * 生成等额本息还款计划
     */
    private void generateEqualInstallmentPlans(List<LoanRepaymentPlan> plans, BigDecimal loanAmount, int term, 
                                               BigDecimal monthRate, LocalDate startDate) {
        // 每月还款 = 贷款本金 × 月利率 × (1+月利率^贷款月数 / [(1+月利率^贷款月数 - 1]
        double monthlyPayment = calculateEqualInstallmentPayment(loanAmount.doubleValue(), monthRate.doubleValue(), term);
        
        BigDecimal remainingPrincipal = loanAmount;
        
        for (int i = 1; i <= term; i++) {
            LoanRepaymentPlan plan = new LoanRepaymentPlan();
            plan.setTermNo(i);
            plan.setRepayDate(startDate.plusMonths(i));
            
            // 本期利息 = 剩余本金 × 月利率
            BigDecimal interest = remainingPrincipal.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
            
            // 本期应还总额
            BigDecimal payment = new BigDecimal(String.valueOf(monthlyPayment)).setScale(2, RoundingMode.HALF_UP);
            
            // 本期本金 = 本期应还总额 - 本期利息
            BigDecimal principal = payment.subtract(interest);
            
            // 处理最后一期可能的尾差
            if (i == term) {
                principal = remainingPrincipal;
                payment = principal.add(interest);
            }
            
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(principal);
            
            plan.setPrincipal(principal);
            plan.setInterest(interest);
            plan.setRepayAmount(payment);
            plan.setPrincipalBalance(remainingPrincipal);
            
            plans.add(plan);
        }
    }
    
    /**
     * 计算等额本息每月还款
     */
    private double calculateEqualInstallmentPayment(double principal, double monthRate, int term) {
        return principal * monthRate * Math.pow(1 + monthRate, term) / (Math.pow(1 + monthRate, term) - 1);
    }
    
    /**
     * 生成等额本金还款计划
     */
    private void generateEqualPrincipalPlans(List<LoanRepaymentPlan> plans, BigDecimal loanAmount, int term, 
                                             BigDecimal monthRate, LocalDate startDate) {
        // 每月本金 = 贷款本金 / 贷款月数
        BigDecimal monthlyPrincipal = loanAmount.divide(new BigDecimal(term), 2, RoundingMode.HALF_UP);
        
        BigDecimal remainingPrincipal = loanAmount;
        
        for (int i = 1; i <= term; i++) {
            LoanRepaymentPlan plan = new LoanRepaymentPlan();
            plan.setTermNo(i);
            plan.setRepayDate(startDate.plusMonths(i));
            
            // 本期本金(最后一期处理尾差
            BigDecimal principal = (i == term) ? remainingPrincipal : monthlyPrincipal;
            
            // 本期利息 = 剩余本金 × 月利率
            BigDecimal interest = remainingPrincipal.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
            
            // 本期应还总额 = 本期本金 + 本期利息
            BigDecimal payment = principal.add(interest);
            
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(principal);
            
            plan.setPrincipal(principal);
            plan.setInterest(interest);
            plan.setRepayAmount(payment);
            plan.setPrincipalBalance(remainingPrincipal);
            
            plans.add(plan);
        }
    }
    
    /**
     * 生成先息后本还款计划
     */
    private void generateInterestFirstPlans(List<LoanRepaymentPlan> plans, BigDecimal loanAmount, int term, 
                                            BigDecimal monthRate, LocalDate startDate) {
        // 每月利息 = 贷款本金 × 月利率
        BigDecimal monthlyInterest = loanAmount.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
        
        for (int i = 1; i <= term; i++) {
            LoanRepaymentPlan plan = new LoanRepaymentPlan();
            plan.setTermNo(i);
            plan.setRepayDate(startDate.plusMonths(i));
            
            // 是否最后一期
            boolean isLastTerm = (i == term);
            
            // 本金和利息
            BigDecimal principal = isLastTerm ? loanAmount : BigDecimal.ZERO;
            BigDecimal interest = monthlyInterest;
            
            // 本期应还总额
            BigDecimal payment = principal.add(interest);
            
            // 剩余本金
            BigDecimal remainingPrincipal = isLastTerm ? BigDecimal.ZERO : loanAmount;
            
            plan.setPrincipal(principal);
            plan.setInterest(interest);
            plan.setRepayAmount(payment);
            plan.setPrincipalBalance(remainingPrincipal);
            
            plans.add(plan);
        }
    }
    
    /**
     * 生成一次性还本付息还款计划
     */
    private void generateBulletPlans(List<LoanRepaymentPlan> plans, BigDecimal loanAmount, int term, 
                                      BigDecimal monthRate, LocalDate startDate) {
        // 一次性还本付息，只有一期
        LoanRepaymentPlan plan = new LoanRepaymentPlan();
        plan.setTermNo(1);
        plan.setRepayDate(startDate.plusMonths(term));
        
        // 利息 = 贷款本金 × 月利率 × 期数
        BigDecimal interest = loanAmount.multiply(monthRate).multiply(new BigDecimal(term)).setScale(2, RoundingMode.HALF_UP);
        
        // 本期应还总额 = 本金 + 利息
        BigDecimal payment = loanAmount.add(interest);
        
        plan.setPrincipal(loanAmount);
        plan.setInterest(interest);
        plan.setRepayAmount(payment);
        plan.setPrincipalBalance(BigDecimal.ZERO);
        
        plans.add(plan);
    }
    
    /**
     * 生成合同编号
     * @return 合同编号
     */
    private String generateContractNo() {
        String prefix = "HT" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        
        // 查询当日最大编号
        String maxNo = contractMapper.selectMaxContractNo();
        
        int sequence = 1;
        if (maxNo != null && maxNo.startsWith(prefix)) {
            try {
                // 提取序号部分
                String sequencePart = maxNo.substring(prefix.length());
                sequence = Integer.parseInt(sequencePart) + 1;
            } catch (Exception e) {
                log.error("解析合同编号序列号失败", e);
            }
        }
        
        // 格式化为4位数字
        return prefix + String.format("%04d", sequence);
    }
    
    /**
     * 保存合同附件
     * @param contractId 合同ID
     * @param attachments 附件列表
     */
    private void saveAttachments(Long contractId, List<ContractSignDTO.AttachmentDTO> attachments) {
        if (attachments == null || attachments.isEmpty()) {
            return;
        }
        
        // 确保上传目录存在
        String contractDir = uploadPath + "/contract/" + contractId;
        File dir = new File(contractDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        for (ContractSignDTO.AttachmentDTO attachment : attachments) {
            try {
                // 生成文件名
                String fileName = attachment.getName();
                String fileType = getFileType(fileName);
                String filePath = contractDir + "/" + System.currentTimeMillis() + "_" + fileName;
                
                // 解码Base64并保存文件
                byte[] fileContent = Base64.getDecoder().decode(attachment.getContent());
                Files.write(Paths.get(filePath), fileContent);
                
                // 保存附件记录
                ContractAttachment contractAttachment = new ContractAttachment();
                contractAttachment.setContractId(contractId);
                contractAttachment.setFileName(fileName);
                contractAttachment.setFilePath(filePath);
                contractAttachment.setFileType(fileType);
                contractAttachment.setFileSize((long) fileContent.length);
                contractAttachment.setUploadTime(LocalDateTime.now());
                
                attachmentMapper.insert(contractAttachment);
                
            } catch (IOException e) {
                log.error("保存合同附件失败", e);
                throw new RuntimeException("保存合同附件失败: " + e.getMessage());
            }
        }
    }
    
    /**
     * 根据文件名获取文件类型
     * @param fileName 文件名
     * @return 文件类型
     */
    private String getFileType(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "application/octet-stream";
        }
        
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        switch (extension) {
            case "pdf":
                return "application/pdf";
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "doc":
                return "application/msword";
            case "docx":
                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case "xls":
                return "application/vnd.ms-excel";
            case "xlsx":
                return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            default:
                return "application/octet-stream";
        }
    }
    
    /**
     * 根据状态字符串获取状态码
     * @param status 状态字符串
     * @return 状态码
     */
    private Integer getStatusCodeByString(String status) {
        if (status == null) {
            return null;
        }
        
        switch (status) {
            case "pending":
                return 10;
            case "signed":
                return 20;
            case "effective":
                return 30;
            case "completed":
                return 40;
            case "terminated":
                return 50;
            default:
                return null;
        }
    }
}
